package tools

import (
	"fmt"
	"gitee.com/igolang/pkg/xhttp"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

func SetAttachmentResponseHeader(ctx *gin.Context, filename string) {
	name := url.QueryEscape(filename)
	ctx.Header(xhttp.HeaderAccessControlExposeHeaders, "Content-Disposition,download-filename")
	ctx.Header("download-filename", name)
	ctx.Header(xhttp.HeaderContentDisposition, fmt.Sprintf(
		"attachment; filename=%s;filename*=utf-8''%s",
		name,
		name,
	))
}

const (
	fileChunk = 10240 // 10kb
)

func DownloadFile(ctx *gin.Context, filename string) error {
	fi, err := os.Stat(filename)
	if err != nil {
		return err
	}
	fh, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer fh.Close()
	outFileName := strings.ReplaceAll(filename, filepath.Dir(filename)+"/", "")
	start := strings.Index(outFileName, "_UPLOAD")
	end := strings.LastIndex(outFileName, ".")
	if end == -1 {
		outFileName = outFileName[:start]
	} else {
		outFileName = outFileName[:start] + outFileName[end:]
	}
	SetAttachmentResponseHeader(ctx, outFileName)
	ctx.Header(xhttp.HeaderContentType, xhttp.MIMEOctetStream)
	ctx.Header(xhttp.HeaderContentLength, cast.ToString(fi.Size()))
	ctx.Status(http.StatusOK)
	b := make([]byte, fileChunk)
	for {
		n, err := fh.Read(b)
		if err != nil && err != io.EOF {
			return err
		}

		if n == 0 || err == io.EOF {
			break
		}

		ctx.Writer.Write(b[:n])
	}
	ctx.Writer.Flush()
	return nil
}

func OutFile(ctx *gin.Context, filename string) error {
	n := strings.LastIndex(filename, ".")
	if n == -1 {
		return DownloadFile(ctx, filename)
	}
	blobType := xhttp.BlobType[strings.ToLower(filename[n+1:])]
	if blobType == "" {
		return DownloadFile(ctx, filename)
	}
	fi, err := os.Stat(filename)
	if err != nil {
		return err
	}
	fh, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer fh.Close()
	b := make([]byte, fileChunk)
	ctx.Header(xhttp.HeaderContentType, blobType)
	ctx.Header(xhttp.HeaderContentLength, cast.ToString(fi.Size()))
	ctx.Status(http.StatusOK)
	for {
		n, err := fh.Read(b)
		if err != nil && err != io.EOF {
			return err
		}
		if n == 0 || io.EOF == err {
			break
		}
		ctx.Writer.Write(b[:n])
	}
	ctx.Writer.Flush()
	return nil
}
